/**
 * @Project : algorithm-learning
 * @Author : Ruoyu Wang
 * @User : Momenta
 * @DateTime : 2024/4/10 17:54
 */

//小明想要处理一批图片，将相似的图片分类。他首先对图片的特征采样，得到图片之间的相似度，然后按照以下规则判断图片是否可以归为一类:
//
//1)相似度>0表示两张图片相似，
//2)如果A和B相似，B和C相似，但A和C不相似。那么认为A和C间接相似，可以把ABC归为一类，但不计算AC的相似度
//3)如果A和所有其他图片都不相似，则A自己归为一类，相似度为0.给定一个大小为NxN的矩阵M存储任意两张图片的相似度，M[i][j]即为第i个图片和第j个图片的相似度，请按照"从大到小”的顺序返回每个相似类中所有图片的相似度之和。
//
//1.0<N<=900
//2.0<=M[i][j]<=100,输入保证M[i][i] =0,M[i][j]=M[j][i]
//
//输入
//第一行一个数N，代表矩阵M中有N个图片，下面跟着N行，每行有N列数据，空格分隔(为了显示整弃，空格可能为多个) 代表N个图片之间的相似度。
//输出
//每个相似类的相似度之和。格式为:一行数字，分隔符为1个空格。
//
//样例1
//输入
//5
//0 0 50 0 0
//0 0 0 25 0
//50 0 0 0 15
//0 25 0 0 0
//0 0 15 0 0
//输出
//65 25
//
//样例2
//输入
//5
//0 5 42 0 0
//5 0 0 91 0
//42 0 0 0 15
//0 91 0 0 0
//0 0 15 0 0
//输出
//153


#include<iostream>
#include<vector>
#include<algorithm>
#include<unordered_map>

using namespace std;

const int N = 910;
int g[N][N];
int n;
int p[N];

int find(int x) {
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            cin >> g[i][j];

    for (int i = 1; i <= n; i++) {
        p[i] = i;
    }

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (g[i][j]) {
                int a = find(i), b = find(j);
                if (a != b) {
                    p[a] = b;
                }
            }
        }
    }

    vector<int> ans;
    unordered_map<int, vector<int>> hash;
    for (int i = 1; i <= n; i++) {
        int x = find(i);
        hash[x].push_back(i);
    }

    for (auto x: hash) {
        auto nos = x.second;
        int res = 0;
        for (int i = 0; i < nos.size(); i++) {
            int a = nos[i];
            for (int j = 0; j < nos.size() && nos[j] != a; j++) {
                int b = nos[j];
                if (g[a][b] && g[b][a]) {
                    res += g[a][b];
                }
            }
        }
        ans.push_back(res);
    }


    sort(ans.begin(), ans.end());
    reverse(ans.begin(), ans.end());

    for (int i = 0; i < ans.size(); ++i) {
        cout << ans[i] << " ";
    }
}

//5
//0 0 50 0 0
//0 0 0 25 0
//50 0 0 0 15
//0 25 0 0 0
//0 0 15 0 0
//65 25

//5
//0 5 42 0 0
//5 0 0 91 0
//42 0 0 0 15
//0 91 0 0 0
//0 0 15 0 0
//153